home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / CUGUK / PROG_TOO / C023A.ZIP / PART2 / ZOPT0.C < prev    next >
Text File  |  1990-01-31  |  9KB  |  454 lines

  1. /*
  2.  * zopt - five pass optimiser for small-C  (general routines)
  3.  *        v2.0 - uses independent processes
  4.  *
  5.  * usage: zopt [-c] source-file
  6.  *        source-file is assumed to have extension .asm
  7.  *
  8.  *        -c  generate compact code by not expanding library routines
  9.  *
  10.  *
  11.  * Bug reports, bug fixes and comments should be addressed to the author:
  12.  *
  13.  *    R M Yorston
  14.  *    1 Church Terrace
  15.  *    Lower Field Road
  16.  *    Reading
  17.  *    RG1 6AS
  18.  *
  19.  */
  20.  
  21. #include <stdio.h>
  22. #include <string.h>
  23.  
  24. #define TRUE    1
  25. #define FALSE    0
  26.  
  27. #define NULL    0
  28. #define CTRLC    3
  29. #define TAB        9
  30. #define SPACE    32
  31.  
  32. #define CONIN    6
  33.  
  34. #define LINELEN 128
  35.  
  36. extern int getopt() ;
  37. extern int optind ;
  38.  
  39. int Ichan, Ochan ;
  40. int Total ;
  41. int Compact ;
  42.  
  43.  
  44. /* pointers to strings to be matched */
  45. char Pophl[] = "\tPOP HL";
  46. char Pushhl[] = "\tPUSH HL";
  47. char Popde[] = "\tPOP DE";
  48. char Pushde[] = "\tPUSH DE";
  49. char Popbc[] = "\tPOP BC";
  50. char Pushbc[] = "\tPUSH BC";
  51. char Ret[] = "\tRET";
  52. char Ldde[] = "\tLD DE," ;
  53. char Ldhl[] = "\tLD HL,";
  54. char Ldhl0[] = "\tLD HL,0";
  55. char Ldhl2[] = "\tLD HL,2";
  56. char Ldhl4[] = "\tLD HL,4";
  57. char Ldhl6[] = "\tLD HL,6";
  58. char Inchl[] = "\tINC HL";
  59. char Dechl[] = "\tDEC HL";
  60. char Popix[] = "\tPOP IX";
  61. char Pushix[] = "\tPUSH IX";
  62. char Exdehl[] = "\tEX DE,HL";
  63. char Addhlde[] = "\tADD HL,DE";
  64. char Addhlhl[] = "\tADD HL,HL";
  65.  
  66.  
  67. usage()
  68. {
  69.     puts( "usage: zopt [-c] file\n" ) ;
  70.     exit() ;
  71. }
  72.  
  73. main( argc, argv )
  74. int argc ;
  75. char **argv ;
  76. {
  77.     char file1[20], file2[20] ;
  78.     int i, c ;
  79.  
  80.     if ( argc == 1 || argc > 3 ) {
  81.         usage() ;
  82.     }
  83.     Compact = FALSE ;
  84.     while ( (c=getopt(argc, argv, "C")) != EOF ) {
  85.         switch ( c ) {
  86.         case 'C' :
  87.             Compact = TRUE ;
  88.             break ;
  89.         default :
  90.             usage() ;
  91.         }
  92.     }
  93.     if ( argc-optind != 1 ) {
  94.         usage() ;
  95.     }
  96.     strcpy( file1, argv[optind] ) ;
  97.     strcat( file1, ".asm" ) ;
  98.     strcpy( file2, argv[optind] ) ;
  99.     strcat( file2, ".$$$") ;
  100.  
  101.     if ( (Ichan=fopen(file1, "r")) == 0 ) {
  102.         err("cannot open input file");
  103.         exit() ;
  104.     }
  105.  
  106.     if ( (Ochan=fopen(file2, "w")) == 0 ) {
  107.         err("cannot open output file");
  108.         exit() ;
  109.     }
  110.  
  111.     Total = 0 ;
  112.  
  113.     /* start processing */
  114.     init() ;
  115.     
  116.     fclose(Ichan) ;
  117.     fclose(Ochan) ;
  118.  
  119.     puts("Grand total bytes saved: ") ; putdec(Total) ;
  120.     putchar('\n') ; putchar('\n') ;
  121.  
  122.     unlink(file1) ;
  123.     rename(file2, file1) ;
  124.  
  125. }
  126.  
  127. extern _newfcb() ;
  128.  
  129. /*
  130.  * rename - rename a named file
  131.  *
  132.  *          return NULL on success, -1 on failure
  133.  */
  134. rename(oldname, newname)
  135. char *oldname, *newname ;
  136. {
  137.     char fcb[56] ;
  138.  
  139.     if ( _newfcb(oldname, fcb) == 0 )
  140.         return -1 ;
  141.     if ( _newfcb(newname, &fcb[16]) == 0 )
  142.         return -1 ;
  143.     if ( cpm(23, fcb) != 0 )
  144.         return -1 ;
  145.     return 0 ;
  146. }
  147.  
  148. /*
  149.  * getline - fetch line from input channel
  150.  *           puts line at pointer, returns FALSE on end of file
  151.  *           returns TRUE for successful get
  152.  *           'global' lines are passed through at once
  153.  */
  154. getline(pointer)
  155. char *pointer ;
  156. {
  157.     int ch ;
  158.     char *ptr ;
  159.  
  160.     ptr = pointer ;
  161.     while ( (ch=getc(Ichan)) != EOF ) {
  162.         if( ch == '\n' ) {
  163.             *pointer = NULL ;
  164.             if ( match("\tglobal", ptr) ) {
  165.                 /* line is 'global' statement, pass it through at once */
  166.                 putline(ptr) ;
  167.                 return getline(ptr) ;
  168.             }
  169.             return TRUE ;
  170.         }
  171.         else
  172.             *pointer++ = ch ;
  173.     }
  174.     *pointer = NULL ;
  175.     return FALSE ;
  176. }
  177.  
  178. /*
  179.  * putline - send line to output file
  180.  */
  181. putline(pointer)
  182. char *pointer ;
  183. {
  184.     if ( fputs(pointer, Ochan) == EOF ) {
  185.         err( "write error in putline, disk full?" ) ;
  186.         exit() ;
  187.     }
  188.     putc('\n', Ochan) ;
  189. }
  190.  
  191. /*
  192.  * Output a signed decimal number
  193.  */
  194. putdec(n)
  195. int n;
  196. {
  197.     if ( n < 0 ) {
  198.         n = -n ;
  199.         putchar('-') ;
  200.     }
  201.     if ( (n/10) != 0 )
  202.         putdec(n/10) ;
  203.     putchar(n%10+'0') ;
  204. }
  205.  
  206. /*
  207.  * allnum - checks if string consists entirely of decimal numbers
  208.  *          returns TRUE if it does
  209.  */
  210. allnum(string)
  211. char *string ;
  212. {
  213.     while ( *string ) {
  214.         if ( (*string<'0') || (*string>'9') ) {
  215.             return FALSE ;
  216.         }
  217.         ++string ;
  218.     }
  219.     return TRUE ;
  220. }
  221.  
  222. /* print total bytes saved */
  223.  
  224. pr_total(i)
  225. int i;
  226. {
  227.     puts("Total bytes saved: ") ; putdec(i) ;
  228.     putchar('\n') ; putchar('\n') ;
  229. }
  230.  
  231. /*
  232.  * islower - returns TRUE if character is lower case, else FALSE
  233.  */
  234. islower(ch)
  235. char ch ;
  236. {
  237.     return (ch >= 'a') & (ch <= 'z') ;
  238. }
  239.  
  240. #ifndef Z80
  241.  
  242. /*
  243.  * match - match token against string
  244.  *         returns NULL if no match
  245.  *         else returns pointer to tail of string
  246.  */
  247. match(token, input)
  248. char *token, *input ;
  249. {
  250.     while ( *input++ == *token++ ) ;
  251.     --token ;
  252.     if ( *token == NULL )
  253.         return --input ;
  254.     else
  255.         return NULL ;
  256. }
  257.  
  258. #else
  259.  
  260. #asm
  261. qmatch:
  262.     POP BC
  263.     POP HL        ;HL is input
  264.     POP DE        ;DE is token
  265.     PUSH DE
  266.     PUSH HL
  267.     PUSH BC
  268. match1:
  269.     LD A,(DE)    ;fetch *token
  270.     CP (HL)
  271.     JR NZ,match2    ;return if *token != *input
  272.     INC HL
  273.     INC DE
  274.     JR match1
  275. match2:
  276.     OR A
  277.     RET Z        ;return input if *token == NULL
  278.     LD HL,0        ;else return 0
  279.     RET
  280. #endasm
  281.  
  282. #endif
  283.  
  284. /***************************************************************************************/
  285. /*                                                                                     */
  286. /* context switching routines                                                          */
  287. /*                                                                                     */
  288. /***************************************************************************************/
  289.  
  290. /* there are six contexts: original, passes 1, 2, 3, 4, 5 */
  291. #define NUMCONTEXT 6
  292.  
  293. /* stack size for processes */
  294. #define STACKSIZE 1024
  295.  
  296. int switch_up(), switch_down() ;
  297.  
  298. int *sp[NUMCONTEXT+1] ;        /* last SP value for each context, zero for last */
  299. int current ;                /* current context */
  300.  
  301. /*
  302.  * switch_up - move up a context level
  303.  *             the argument str is the return value passed to the parent
  304.  *             str may not be zero
  305.  */
  306. switch_up(str)
  307. char *str ;
  308. {
  309. #asm
  310.     ld hl,(qcurrent)        ; sp[current--] = SP
  311.     dec hl
  312.     ld (qcurrent),hl
  313.     inc hl
  314.     add hl,hl
  315.     ex de,hl
  316.     ld ix,qsp
  317.     add ix,de                ; (IX = &sp[current])
  318.     ld hl,0
  319.     add hl,sp
  320.     ld (ix),l
  321.     ld (ix+1),h
  322.     inc hl                    ; (DE = str) need to get this before switch
  323.     inc hl
  324.     ld e,(hl)
  325.     inc hl
  326.     ld d,(hl)
  327.     ld h,(ix-1)                ; SP = sp[current]
  328.     ld l,(ix-2)
  329.     ld sp,hl
  330.     ex de,hl                ; return str
  331.     ret
  332. #endasm
  333. }
  334.  
  335.  
  336. /*
  337.  * switch_down - move down a context level
  338.  *               the argument str is the return value passed to the child
  339.  *               str may not be zero
  340.  */
  341. switch_down(str)
  342. char *str ;
  343. {
  344.     if ( sp[current+1] == 0 )
  345.         return 0 ;
  346. #asm
  347.     ld hl,(qcurrent)        ; sp[current++] = SP
  348.     inc hl
  349.     ld (qcurrent),hl
  350.     dec hl
  351.     add hl,hl
  352.     ex de,hl
  353.     ld ix,qsp
  354.     add ix,de                ; (IX = &sp[current])
  355.     ld hl,0
  356.     add hl,sp
  357.     ld (ix),l
  358.     ld (ix+1),h
  359.     inc hl                    ; (DE = str) need to get this before switch
  360.     inc hl
  361.     ld e,(hl)
  362.     inc hl
  363.     ld d,(hl)
  364.     ld l,(ix+2)                ; SP = sp[current]
  365.     ld h,(ix+3)
  366.     ld sp,hl
  367.     ex de,hl                ; return str
  368.     ret
  369. #endasm
  370. }
  371.  
  372. /*
  373.  * die - routine to force proper termination of a process when it
  374.  *       falls out of its closing brace
  375.  *       makes repeated calls to its child with an argument of 0
  376.  *       until child returns 0 too, to indicate its death
  377.  *       then set remembered SP for this level to zero and switches up
  378.  *       with a zero return value
  379.  */
  380. die()
  381. {
  382.     while ( switch_down(0) )
  383.         ;
  384.     sp[current] = 0 ;
  385.     switch_up(0) ;
  386. }
  387.  
  388. /*
  389.  * read data from parent process to string t
  390.  * returns 0 on end of file, puts null string in t
  391.  */
  392. char *p_read() ;
  393. p_read(t)
  394. char *t ;
  395. {
  396.     char *s ;
  397.  
  398.     if ( (s=switch_up(1)) == 0 ) {
  399.         *t = '\000' ;
  400.         return 0 ;
  401.     }
  402.     strcpy(t, s) ;
  403. }
  404.  
  405. /*
  406.  * write data to child process
  407.  */
  408. c_write(s)
  409. char *s ;
  410. {
  411.     switch_down(s) ;
  412. }
  413.  
  414. init()
  415. {
  416.     /* sp[0] will be set up by first context switch */
  417.  
  418.     /* make space for process 1's stack */
  419.     sp[1] = alloc(STACKSIZE) + (STACKSIZE-2*sizeof(int)) ;
  420.     /* initialise stack for process 1 */
  421.     sp[1][0] = pass1 ;
  422.     sp[1][1] = die ;
  423.  
  424.     /* make space for process 2's stack */
  425.     sp[2] = alloc(STACKSIZE) + (STACKSIZE-2*sizeof(int)) ;
  426.     /* initialise stack for process 2 */
  427.     sp[2][0] = pass2 ;
  428.     sp[2][1] = die ;
  429.  
  430.     /* make space for process 3's stack */
  431.     sp[3] = alloc(STACKSIZE) + (STACKSIZE-2*sizeof(int)) ;
  432.     /* initialise stack for process 3 */
  433.     sp[3][0] = pass3 ;
  434.     sp[3][1] = die ;
  435.  
  436.     /* make space for process 4's stack */
  437.     sp[4] = alloc(STACKSIZE) + (STACKSIZE-2*sizeof(int)) ;
  438.     /* initialise stack for process 4 */
  439.     sp[4][0] = pass4 ;
  440.     sp[4][1] = die ;
  441.  
  442.     /* make space for process 5's stack */
  443.     sp[5] = alloc(STACKSIZE) + (STACKSIZE-2*sizeof(int)) ;
  444.     /* initialise stack for process 5 */
  445.     sp[5][0] = pass5 ;
  446.     sp[5][1] = die ;
  447.  
  448.     /* mark end of processes */
  449.     sp[6] = 0 ;
  450.  
  451.     /* get the show on the road */
  452.     switch_down(1) ;
  453. }
  454.